package com.starsoft.smdc.service;

import static com.starsoft.frame.util.NumberUtil.addNullable;
import static com.starsoft.frame.util.NumberUtil.null2Zero;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.starsoft.frame.core.orm.PageObject;
import com.starsoft.frame.util.DateUtil;
import com.starsoft.frame.util.MapUtil;
import com.starsoft.smdc.bean.SmdcDiv;
import com.starsoft.smdc.bean.SmdcDivId;
import com.starsoft.smdc.bean.SmdcMarketDaily;
import com.starsoft.smdc.bean.SmdcSecurity;
import com.starsoft.smdc.dao.DivDao;
import com.starsoft.smdc.dao.SmdcSecurityDao;
import com.starsoft.smdc.util.SecurityType;

@Service
public class DivService {

	@Autowired
	DivDao divDao;
	
	@Autowired
	SmdcSecurityDao securityDao;
	
	@Autowired
	ErService erService;
	
	@Autowired
	MarketDailyService marketDailyService;
	
	public void delete(SmdcDiv div) {
		SmdcSecurity security = securityDao.get(div.getId().getSecId());
		divDao.delete(div);
		if (div.getEarningDate() != null) {
			erService.update(security, div.getEarningDate());
		}
		marketDailyService.updateAdjFactor(security, div.getId().getDivDate());
	}
	
	public void save(SmdcDiv div){
		SmdcSecurity security = securityDao.get(div.getId().getSecId());
		divDao.saveOrUpdate(div);
		if (div.getEarningDate() != null) {
			erService.update(security, div.getEarningDate());
		}
		marketDailyService.updateAdjFactor(security, div.getId().getDivDate());
	}
	
	public Date getBeginDate(SmdcSecurity security){
		Date beginDate = divDao.getMaxDivDate(security);
		if(beginDate == null){
			beginDate = securityDao.getBeginDate(security);
		}else{
			beginDate = DateUtil.getNext(beginDate);
		}
		return beginDate;
	}

	public List<SmdcDiv> getPbDateBefore(SmdcSecurity security, Date endDate) {
		return divDao.getPbDateBefore(security, endDate);
	}
	
	/**
	 * get the first SmdcDiv before divDate
	 * @param security
	 * @param endDate
	 * @return
	 */
	public SmdcDiv getDivDateBeforeOne(SmdcSecurity security, Date endDate) {
		return divDao.getDivDateBeforeOne(security, endDate);
	}
	
	public List<SmdcDiv> getDivDateAfter(SmdcSecurity security, Date beginDate){
		return divDao.getDivDateAfter(security, beginDate);
	}
	
	public List<SmdcDiv> getDivDateBetween(SmdcSecurity security, Date beginDate, Date endDate){
		return divDao.getDivDateBetween(security, beginDate, endDate);
	}
	 
	public SmdcDiv get(String secId, Date divDate){
		SmdcDivId id = new SmdcDivId(secId, divDate);
		return divDao.get(id);
	}

	@SuppressWarnings("unchecked")
	public Map<String, Object> pageQuery(PageObject po, String secId, Date beginDate, Date endDate) {
		Map<String, Object> result = divDao.pageQuery(po, secId, beginDate, endDate);
		List<SmdcDiv> rows = po.getRows();
		List<Object> newRows = new ArrayList<>();
		for(SmdcDiv div:rows){
			newRows.add(this.convertBean(div));
		}
		result.put("rows", newRows);
		return result;
	}
	
	public Map<String, Object> convertBean(SmdcDiv div){
		Map<String, Object> result = MapUtil.toMap(div);
		result.remove("id");
		result.put("divDate", div.getId().getDivDate());
		result.put("secId", div.getId().getSecId());
		result.put("secName", securityDao.get(div.getId().getSecId()).getSecName());
		return result;
	}
	
	public double caculateShareFactor(double oldFactor, SmdcDiv div) {
		double factor = addNullable(1.0, div.getPerShareDiv(), div.getPerShareTrans());
		return factor * oldFactor;
	}
	
	public double caculateFactor(double oldFactor, SmdcDiv div, SmdcMarketDaily market) {
		SmdcSecurity security = securityDao.get(market.getId().getSecId());
		SecurityType secType = SecurityType.get(security);
		Double cash = null;
		if(secType == SecurityType.bond || secType == SecurityType.fund){
			cash = null2Zero(div.getPerCashDiv());
		} else {
			cash = null2Zero(div.getPerCashDiv());
		}
		Double shares = addNullable(1.0, div.getPerShareDiv(), div.getPerShareTrans()) + cash / market.getClosePrice();
		return shares * oldFactor;
	}
	
}
